﻿// MyProject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//公众号：程序员速成 ，内含一辈子都让你感激自己的优质视频教程，欢迎关注

#include <iostream>
#include <map>


#ifdef _DEBUG   //只在Debug（调试）模式下
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace _nmsp1
{
	//UI控件类的父类
	class CtlParent
	{
	public:
		CtlParent(string caption) :m_caption(caption) {} //构造函数
		virtual ~CtlParent() {} //做父类时析构函数应该为虚函数

	public:
		//当UI控件发生变化时该成员函数会被调用
		virtual void Changed(map<string, CtlParent*>& tmpuictllist) = 0; //形参所代表的map容器中包含着所有对话框中涉及的UI控件。
		//设置UI控件启用或者禁用
		virtual void Enable(bool sign) = 0;

	protected:
		string m_caption; //控件上面显示的文字内容，本范例假设每个UI空间上的文字都不同
	};

	//普通按钮相关类
	class Button :public CtlParent
	{
	public:
		Button(string caption) :CtlParent(caption) {} //构造函数
		//设置按钮的启用或者禁用
		virtual void Enable(bool sign)
		{
			if (sign == true)
			{
				cout << "按钮\"" << m_caption << "\"被设置为了\"启用\"状态" << endl;
			}
			else
			{
				cout << "按钮\"" << m_caption << "\"被设置为了\"禁用\"状态" << endl;
			}
			//......具体实现按钮启用或者禁用的代码。。。。
		}
		//按钮被按下时该成员函数会被调用
		virtual void Changed(map<string, CtlParent*>& tmpuictllist);
	};
	
	//单选按钮相关类
	class RadioBtn :public CtlParent
	{
	public:
		RadioBtn(string caption) :CtlParent(caption) {} //构造函数
		//设置单选按钮的启用或者禁用
		virtual void Enable(bool sign)
		{
			//本范例用不到该功能，实现代码略......
		}
		//设置单选按钮被选中或者被取消选中，被选中的单选按钮中间有个黑色的实心圆点
		void Selected(bool sign)
		{
			if (sign == true)
			{
				cout << "单选按钮\"" << m_caption << "\"被选中" << endl;
			}
			else
			{
				cout << "单选按钮\"" << m_caption << "\"被取消选中" << endl;
			}
			//......具体实现单选按钮启用或者取消选中的代码略。。。。。
		}
		
		//单选按钮被单击时该成员函数会被调用
		virtual void Changed(map<string, CtlParent*>& tmpuictllist);
	};

	//编辑框相关类
	class EditCtl :public CtlParent
	{
	public:
		EditCtl(string caption) :CtlParent(caption) {} //构造函数
		//设置编辑框的启用或者禁用
		virtual void Enable(bool sign)
		{
			if (sign == true)
			{
				cout << "编辑框\"" << m_caption << "\"被设置为了\"启用\"状态" << endl;
			}
			else
			{
				cout << "编辑框\"" << m_caption << "\"被设置为了\"禁用\"状态" << endl;
			}
			//......具体实现编辑框启用或者禁用的代码。。。。
		}

		//是否编辑框中的内容为空
		bool isContentEmpty()
		{
			return m_content.empty();
		}

		//编辑框内容发生变化时该成员函数会被调用
		virtual void Changed(map<string, CtlParent*>& tmpuictllist);

	private:
		string m_content = ""; //编辑框中的内容
	};

	//---------------------------
	//普通按钮被按下是该成员函数会被调用
	void Button::Changed(map<string, CtlParent*>& tmpuictllist)
	{
		if (m_caption == "登录")
		{
			//按下的是登录按钮
			cout << "开始游戏登录验证，根据验证结果决定是否进入游戏之中还是验证失败给出提示！" << endl;
		}
		else if (m_caption == "退出")
		{
			//按下的是退出按钮，则退出整个游戏
			cout << "游戏退出，再见！" << endl;
		}
	}

	//单选按钮被单击时该成员函数会被调用
	void RadioBtn::Changed(map<string, CtlParent*>& tmpuictllist)
	{
		if (m_caption == "游客登录")
		{
			(static_cast<RadioBtn*>(tmpuictllist["游客登录"]))->Selected(true); //游客登录 单选按钮被选中
			(static_cast<RadioBtn*>(tmpuictllist["账号登录"]))->Selected(false); //账号登录 单选按钮被取消选中

			tmpuictllist["账号"]->Enable(false); //账号 编辑框设置为禁用
			tmpuictllist["密码"]->Enable(false); //密码 编辑框设置为禁用

			tmpuictllist["登录"]->Enable(true);  //登录 按钮设置为启用
		}
		else if (m_caption == "账号登录")
		{
			(static_cast<RadioBtn*>(tmpuictllist["账号登录"]))->Selected(true); //账号登录 单选按钮被选中
			(static_cast<RadioBtn*>(tmpuictllist["游客登录"]))->Selected(false); //游客登录 单选按钮被取消选中

			tmpuictllist["账号"]->Enable(true); //账号 编辑框设置为启用
			tmpuictllist["密码"]->Enable(true); //密码 编辑框设置为启用

			if ((static_cast<EditCtl*>(tmpuictllist["账号"]))->isContentEmpty()
				|| (static_cast<EditCtl*>(tmpuictllist["密码"]))->isContentEmpty())
			{
				//如果 账号 编辑框 或者 密码 编辑框 有一个为空，则不允许登录
				tmpuictllist["登录"]->Enable(false); //登录 按钮设置为禁用
			}
			else
			{
				tmpuictllist["登录"]->Enable(true); //登录 按钮设置为启用
			}			
		}
	}

	//编辑框内容发生变化时该成员函数会被调用
	void EditCtl::Changed(map<string, CtlParent*>& tmpuictllist)
	{
		if ((static_cast<EditCtl*>(tmpuictllist["账号"]))->isContentEmpty()
			|| (static_cast<EditCtl*>(tmpuictllist["密码"]))->isContentEmpty())
		{
			//如果 账号 编辑框 或者 密码 编辑框 有一个为空，则不允许登录
			tmpuictllist["登录"]->Enable(false); //登录 按钮设置为禁用
		}
		else
		{
			tmpuictllist["登录"]->Enable(true); //登录 按钮设置为启用
		}
	}
}

int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口

	//第17章 中介者（Mediator）模式：调停者模式，行为型模式。
	//（1）中介者的基本概念
	//a)计算的各个组成部件：主板
	//b)qq聊天：与好友或者陌生人单独聊天（私聊）；加入到一个qq群中。
	//c)飞机的安全飞行与安全着陆：塔台

	//（2）中介者模式范例的引入:事件类驱动的软件中有比较广泛的应用，尤其是常常运用在程序的UI界面设计中


	//创建各种UI控件
	map<string, _nmsp1::CtlParent*> uictllist; //将所有创建的UI控件保存到map容器中，方便进行参数传递
	uictllist["登录"] = new _nmsp1::Button("登录");
	uictllist["退出"] = new _nmsp1::Button("退出");

	uictllist["游客登录"] = new _nmsp1::RadioBtn("游客登录");
	uictllist["账号登录"] = new _nmsp1::RadioBtn("账号登录");

	uictllist["账号"] = new _nmsp1::EditCtl("账号");
	uictllist["密码"] = new _nmsp1::EditCtl("密码");

	//设置一下缺省的UI控件状态
	(static_cast<_nmsp1::RadioBtn*>(uictllist["游客登录"]))->Selected(true); //游客登录 单选按钮被选中
	(static_cast<_nmsp1::RadioBtn*>(uictllist["账号登录"]))->Selected(false); //账号登录 单选按钮被取消选中

	uictllist["账号"]->Enable(false); //账号  编辑框设置为禁用
	uictllist["密码"]->Enable(false); //密码  编辑框设置为禁用

	uictllist["登录"]->Enable(true); //登录  按钮设置为启用
	uictllist["退出"]->Enable(true); //退出  按钮设置为启用

	cout << "------------------------" << endl;
	uictllist["账号登录"]->Changed(uictllist); //模拟 账号登录 单选按钮被单击选中



	//释放资源
	for (auto iter = uictllist.begin(); iter != uictllist.end(); ++iter)
	{
		delete iter->second;
		iter->second = nullptr;
	}


	return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件

